#include "pf.h"

PF_Manager* PF_Manager::_pf_manager = 0;


PF_Manager* PF_Manager::Instance()
{
    if(!_pf_manager)
        _pf_manager = new PF_Manager();
    
    return _pf_manager;    
}


PF_Manager::PF_Manager()
{
}


PF_Manager::~PF_Manager()
{
}

    
RC PF_Manager::CreateFile(const char *fileName)
{
	if(fileName == NULL)
	{
		cout<<"Null parameter passed to CreateFile().";
		return -1;
	}

	if(this->FileExists(fileName))
	{
		cout<<"File already exists."<<endl;
		return -1;
	}
	else
	{
		FILE *file = fopen(fileName, "wb");
		if(file==NULL)
		{
			cout<<"Error in creating file."<<endl;
			return -1;
		}
		else
		{
			if(fclose(file) != 0)
			{
				cout<<"Error in closing file after creation."<<endl;
				return -1;
			}
			else
			{
				// correct exit point for function
				return 0;
			}
		}
	}
}


RC PF_Manager::DestroyFile(const char *fileName)
{
	if(fileName == NULL)
	{
		cout<<"Null parameter passed to DestroyFile().";
		return -1;
	}

	if(this->FileExists(fileName))
	{
		if(remove(fileName) != 0)
		{
			perror("Error deleting file.");
			return -1;
		}
		else
		{
			// correct exit point for function
			return 0;
		}
	}
	else
	{
		cout<<"File does not exists."<<endl;
		return -1;
	}
}


RC PF_Manager::OpenFile(const char *fileName, PF_FileHandle &fileHandle)
{
	if(fileName == NULL)
	{
		cout<<"Null parameter passed to OpenFile().";
		return -1;
	}

	if(this->FileExists(fileName))
	{
			FILE *file = fopen(fileName, "r+b");
			if(file != NULL)
			{
				if(fseek(file, 0, SEEK_END)==0)
				{
					int size = ftell(file);
					fileHandle.setFile(file);

					int numPages = size / PF_PAGE_SIZE;
					if(size % PF_PAGE_SIZE != 0)
					{
						cout<<"Error in opening file, maybe the file was not created using CreatFile() function.";
						return -1;
					}
					else
					{
						fileHandle.setNumPages(numPages);
						fseek(file, 0, SEEK_SET);
						// correct exit point for function
						return 0;
					}
				}
				else
				{
					cout<<"Error while reading file."<<endl;
					return -1;
				}
			}
			else
			{
				cout<<"Error while reading file."<<endl;
				return -1;
			}
	}
	else
	{
		cout<<"File does not exist."<<endl;
		return -1;
	}
}


RC PF_Manager::CloseFile(PF_FileHandle &fileHandle)
{
	FILE *file = fileHandle.getFile();
	if(file != NULL)
	{
		fflush(file);
		fclose(file);
		return 0;
	}
	else
	{
		cout<<"File already closed."<<endl;
		return -1;
	}
}


PF_FileHandle::PF_FileHandle()
{
	this->numOfPages = 0;
}
 

PF_FileHandle::~PF_FileHandle()
{
}


RC PF_FileHandle::ReadPage(PageNum pageNum, void *data)
{
	if(data == NULL)
	{
		cout<<"Null parameter passed to ReadPage().";
		return -1;
	}

	if(pageNum >= GetNumberOfPages() || pageNum < 0)
	{
		cout<<"Page "<< (int)pageNum<<" does not exist"<<endl;
		return -1;
	}

	if(fseek(file, (pageNum * PF_PAGE_SIZE), SEEK_SET) == 0)
	{
		int ret = fread(data, 1, PF_PAGE_SIZE, file);
		return 0;
	}
	else
	{
		cout<<"Error reading from the page: "<< pageNum<<endl;
		return -1;
	}
}


RC PF_FileHandle::WritePage(PageNum pageNum, const void *data)
{
	if(data == NULL)
	{
		cout<<"Null parameter passed to WritePage().";
		return -1;
	}

	if(pageNum >= GetNumberOfPages() || pageNum < 0)
	{
		cout<<"Page "<< (int)pageNum<<" does not exist"<<endl;
		return -1;
	}

	if(fseek(file, (pageNum * PF_PAGE_SIZE), SEEK_SET) == 0)
	{
		int ret = fwrite(data, 1, PF_PAGE_SIZE, file);
		return 0;
	}
	else
	{
		cout<<"Error reading from the page: "<< pageNum<<endl;
		return -1;
	}
}


RC PF_FileHandle::AppendPage(const void *data)
{
	if(data == NULL)
	{
		cout<<"Null parameter passed to AppendPage().";
	}

    if(fseek(file, 0, SEEK_END) == 0)
    {
    	int ret = fwrite(data, 1, PF_PAGE_SIZE, file);
    	setNumPages(GetNumberOfPages()+1);
    	return 0;
    }
    else
    {
    	cout<<"Error while appending page."<<endl;
    	return -1;
    }
}


unsigned PF_FileHandleGetNumberOfPages()
{
	return this->numOfPages;
}


void PF_FileHandle::setFile(FILE *file)
{
	this->file = file;
}


FILE* PF_FileHandle::getFile()
{
	return this->file;
}


RC PF_Manager::FileExists(const char *fileName)
{
	if(fileName == NULL)
	{
		cout<<"Null parameter passed to FileExists().";
		return -1;
	}

	FILE *file = fopen(fileName, "rb");
	if(file != NULL)
	{
		return true;
	}
	else
	{
		return false;
	}
}
